
package com.scott.itcast.condition;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 用Lock实现互斥。用Condition实现通信
 * 线程1(老大)循环10次，接着线程2(老二)循环20次。接着线程3(老三)循环30次。
 * 接着又回到 线程1(老大)循环10次，接着线程2(老二)循环20次。接着线程3(老三)循环30次。
 * 如此循环5次。请写出程序
 * 备注：老大只能唤醒老二。老二只能唤醒老三。老三只能唤醒老大
 */
public class ThreeConditionCommunication {

	public static void main(String[] args) {
		
		
		final Business business = new Business();
		
		final int counter=5;
		//第1个线程
		new Thread(new Runnable(){
			public void run() {
				for(int i=1;i<=counter;i++){
					business.sub1(i);
				}
			}
			
		}).start();
		
		//第2个线程
		new Thread(new Runnable(){
			public void run() {
				for(int i=1;i<=counter;i++){
					business.sub2(i);
				}
			}
			
		}).start();
		
		
		//第3个线程
		new Thread(new Runnable(){
			public void run() {
				for(int i=1;i<=counter;i++){
					business.sub3(i);
				}
			}
			
		}).start();

	}
	
	//加了static的类就相当于外部类
	static class Business{
		
		//重入锁 ReentrantLock 是一种递归无阻塞的同步机制。 实现互斥
		private Lock lock  = new ReentrantLock();
		
		//实现 通信
		private Condition condition1 = lock.newCondition();
		private Condition condition2 = lock.newCondition();
		private Condition condition3 = lock.newCondition();
		
		
		//老大先走
		private int flag = 1;
		
		
		public void sub1(int i){
			lock.lock();
			try{
				//使用while可以消除 伪唤醒  spurious wakeup
				while(flag !=1 ){
					try {
						condition1.await(); //等待
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
				
				for(int j=1; j<=10; j++){
					System.out.println("线程1["+Thread.currentThread().getName()+ "]。外层循环次数：[" + i + "]。内存循环次数：["+j+"]");
				}
				System.out.println();
				flag=2;
				//通知老二开始工作
				condition2.signal();
				
			}finally{
				lock.unlock();
			}
		}//sub1
		
		public void sub2(int i){
			lock.lock();
			try{
				//使用while可以消除 伪唤醒  spurious wakeup
				while(flag != 2){
					try {
						//this.wait();
						condition2.await(); //等待
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
				
				for(int j=1; j<=20; j++){
					System.out.println("线程2["+Thread.currentThread().getName()+ "]。外层循环次数：[" + i + "]。内存循环次数：["+j+"]");
				}
				System.out.println();
				
				flag=3;
				
				//通知老三开始工作
				condition3.signal();
				
			}finally{
				lock.unlock();
			}
		}//sub2
		
		
		public void sub3(int i){
			lock.lock();
			try{
				//使用while可以消除 伪唤醒  spurious wakeup
				while(flag !=3){
					try {
						condition3.await(); //等待
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
				
				for(int j=1; j<=30; j++){
					System.out.println("线程3["+Thread.currentThread().getName()+ "]。外层循环次数：[" + i + "]。内存循环次数：["+j+"]");
				}
				System.out.println();
				flag=1;
				
				//通知老大开始工作
				condition1.signal();
				
			}finally{
				lock.unlock();
			}
		}//sub3

	}//Business
}//ThreeConditionCommunication


